package cn.tedu.lock;

import java.util.concurrent.CountDownLatch;

/**
 * 案例: 考试
 * 考官到达考场
 * 考生到达考场
 * 需要等上面两类角色都到达考场之后,才能开始考试
 */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(7);
        new Thread(new Teacher(cdl)).start();
        new Thread(new Teacher(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();

        // 正常情况下, 应该是上面7个线程执行完成后才能开始考试
        // sout在主函数中, main所在的类默认是一个主线程
        // 实际上, 存在了至少8个线程: 1个主线程, 2个Teacher, 5个Student
        // 在上面7个线程都执行完成之前, 主线程应该陷入阻塞
        // 在计数归零之前, 主线程都会等待
        cdl.await();
        System.out.println("考试开始");
    }
}

/**
 * 考官
 */
class Teacher implements Runnable {
    private CountDownLatch countDownLatch;

    public Teacher(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            // 模拟考官到考场的时间不同
            Thread.sleep((long) Math.random() * 10000);
            System.out.println("考官到达考场");
            // 计数减少一个
            countDownLatch.countDown();
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
    }
}

/**
 * 考生
 */
class Student implements Runnable {
    private CountDownLatch countDownLatch;

    public Student(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            // 模拟考生到考场的时间不同
            Thread.sleep((long) Math.random() * 10000);
            System.out.println("考生到达考场");
            // 计数减少一个
            countDownLatch.countDown();
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
    }
}
